<template>
    <div class="pe-date-calendar">
        <div class="pe-date-calendar-header">
            <div class="pe-date-calendar-flex">
                <i class="pe-icon" @click.stop="preYear">
                    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024">
                        <path fill="currentColor"
                            d="M529.408 149.376a29.12 29.12 0 0 1 41.728 0 30.592 30.592 0 0 1 0 42.688L259.264 511.936l311.872 319.936a30.592 30.592 0 0 1-.512 43.264 29.12 29.12 0 0 1-41.216-.512L197.76 534.272a32 32 0 0 1 0-44.672l331.648-340.224zm256 0a29.12 29.12 0 0 1 41.728 0 30.592 30.592 0 0 1 0 42.688L515.264 511.936l311.872 319.936a30.592 30.592 0 0 1-.512 43.264 29.12 29.12 0 0 1-41.216-.512L453.76 534.272a32 32 0 0 1 0-44.672l331.648-340.224z">
                        </path>
                    </svg>
                </i>
                <i class="pe-icon" @click.stop="preMonth" v-if="yearMonthFlag === 'day'">
                    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024">
                        <path fill="currentColor"
                            d="M609.408 149.376 277.76 489.6a32 32 0 0 0 0 44.672l331.648 340.352a29.12 29.12 0 0 0 41.728 0 30.592 30.592 0 0 0 0-42.752L339.264 511.936l311.872-319.872a30.592 30.592 0 0 0 0-42.688 29.12 29.12 0 0 0-41.728 0z">
                        </path>
                    </svg>
                </i>
            </div>
            <div class="pe-date-calendar-flex">
                <span class="pe-date-calendar-ym" @click="getYearMonth('year')">{{ year }}年</span>
                <span class="pe-date-calendar-ym" @click="getYearMonth('month')" v-if="yearMonthFlag !== 'year'">{{
                    month }}月</span>
            </div>
            <div class="pe-date-calendar-flex">
                <i class="pe-icon" @click.stop="nextMonth" v-if="yearMonthFlag === 'day'">
                    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024">
                        <path fill="currentColor"
                            d="M340.864 149.312a30.592 30.592 0 0 0 0 42.752L652.736 512 340.864 831.872a30.592 30.592 0 0 0 0 42.752 29.12 29.12 0 0 0 41.728 0L714.24 534.336a32 32 0 0 0 0-44.672L382.592 149.376a29.12 29.12 0 0 0-41.728 0z">
                        </path>
                    </svg>
                </i>
                <i class="pe-icon" @click.stop="nextYear">
                    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024">
                        <path fill="currentColor"
                            d="M452.864 149.312a29.12 29.12 0 0 1 41.728.064L826.24 489.664a32 32 0 0 1 0 44.672L494.592 874.624a29.12 29.12 0 0 1-41.728 0 30.592 30.592 0 0 1 0-42.752L764.736 512 452.864 192a30.592 30.592 0 0 1 0-42.688m-256 0a29.12 29.12 0 0 1 41.728.064L570.24 489.664a32 32 0 0 1 0 44.672L238.592 874.624a29.12 29.12 0 0 1-41.728 0 30.592 30.592 0 0 1 0-42.752L508.736 512 196.864 192a30.592 30.592 0 0 1 0-42.688z">
                        </path>
                    </svg>
                </i>
            </div>
        </div>
        <div class="pe-date-calendar-body">
            <table class="pe-date-calendar-table" v-if="yearMonthFlag === 'day'">
                <thead class="pe-date-calendar-thead">
                    <tr>
                        <td>一</td>
                        <td>二</td>
                        <td>三</td>
                        <td>四</td>
                        <td>五</td>
                        <td>六</td>
                        <td>日</td>
                    </tr>
                </thead>
                <tbody class="pe-date-calendar-tbody">
                    <tr v-for="(days, index) in dayList" :key="index">
                        <td v-for="day in days" :key="day.index"
                            :class="[day.active ? 'pe-date-calendar-active' : '', day.thisMonth === 'this' ? '' : 'pe-date-calendar-not']"
                            @click="onClick(day.index)">
                            <div class="pe-date-calendar-day">{{ day.value }}</div>
                        </td>
                    </tr>
                </tbody>
            </table>
            <div class="pe-date-calendar-item" v-if="yearMonthFlag === 'year'">
                <div class="pe-item" v-for="item in yearList" :class="[item === year ? 'pe-active' : '']"
                    @click="clickYear(item)">{{ item }}</div>
            </div>
            <div class="pe-date-calendar-item" v-if="yearMonthFlag === 'month'">
                <div class="pe-item" v-for="item in monthList" :class="[item === month ? 'pe-active' : '']"
                    @click="clickMonth(item)">{{ item }}月</div>
            </div>
        </div>
    </div>
</template>

<script setup lang="ts">
import { onBeforeMount, reactive, ref, watch } from "vue"
import dayjs from 'dayjs';

const show = defineModel<boolean>("show")
const date = defineModel<string>("date")
const dateModel = defineModel<string | Date | number>("dateModel")

interface Props {
    type?: 'datestr' | 'date' | 'timestamp',
    format?: string,
    valueFormat?: string
}

const props = withDefaults(defineProps<Props>(), {
    type: "datestr",
    format: "YYYY-MM-DD",
    valueFormat: "YYYY-MM-DD"
})

// 显示的年月
const year = ref<number>(0)
const month = ref<number>(0)

// 选择的年月日
const activeYear = ref<number>(0)
const activeMonth = ref<number>(0)
const activeDay = ref<number>(0)

onBeforeMount(() => {
    if (dateModel.value) {
        const date1 = new Date(dateModel.value)
        formatDate(date1.getFullYear(), date1.getMonth() + 1, date1.getDate())
    } else {
        formatDate(0)
    }
})

// 格式化后的日期处理
const formatDate = (paramYear: number, paramMonth?: number, paramDay?: number) => {
    let date1 = new Date()
    if (paramYear) {
        date1 = new Date(`${paramYear}-${paramMonth}-${paramDay}`)
        date.value = dayjs(date1).format(props.format)
    }
    year.value = date1.getFullYear()
    month.value = date1.getMonth() + 1
    activeYear.value = year.value
    activeMonth.value = month.value
    activeDay.value = date1.getDate()
    if (props.type === 'timestamp') {
        dateModel.value = new Date(`${dayjs(date1).format('YYYY-MM-DD')} 00:00:00`).getTime()
    } else if (props.type === 'date') {
        dateModel.value = date1
    } else {
        dateModel.value = dayjs(date1).format(props.valueFormat)
    }
}

/**
 * @param index 唯一标识
 * @param value 日
 * @param active 是否选中
 * @param thisMonth 是否本月(this: 本月, pre: 上个月, next: 下个月)
 */
interface DayInterface {
    index: number,
    value: number,
    active: boolean,
    thisMonth: 'this' | 'pre' | 'next'
}

const dayList = reactive<Array<Array<DayInterface>>>([
    [
        {
            index: 1,
            value: 1,
            active: false,
            thisMonth: 'this'
        }, {
            index: 2,
            value: 1,
            active: false,
            thisMonth: 'this'
        }, {
            index: 3,
            value: 1,
            active: false,
            thisMonth: 'this'
        }, {
            index: 4,
            value: 1,
            active: false,
            thisMonth: 'this'
        }, {
            index: 5,
            value: 1,
            active: false,
            thisMonth: 'this'
        }, {
            index: 6,
            value: 1,
            active: false,
            thisMonth: 'this'
        }, {
            index: 7,
            value: 1,
            active: false,
            thisMonth: 'this'
        }
    ], [
        {
            index: 8,
            value: 1,
            active: false,
            thisMonth: 'this'
        }, {
            index: 9,
            value: 1,
            active: false,
            thisMonth: 'this'
        }, {
            index: 10,
            value: 1,
            active: false,
            thisMonth: 'this'
        }, {
            index: 11,
            value: 1,
            active: false,
            thisMonth: 'this'
        }, {
            index: 12,
            value: 1,
            active: false,
            thisMonth: 'this'
        }, {
            index: 13,
            value: 1,
            active: false,
            thisMonth: 'this'
        }, {
            index: 14,
            value: 1,
            active: false,
            thisMonth: 'this'
        }
    ], [
        {
            index: 15,
            value: 1,
            active: false,
            thisMonth: 'this'
        }, {
            index: 16,
            value: 1,
            active: false,
            thisMonth: 'this'
        }, {
            index: 17,
            value: 1,
            active: false,
            thisMonth: 'this'
        }, {
            index: 18,
            value: 1,
            active: false,
            thisMonth: 'this'
        }, {
            index: 19,
            value: 1,
            active: false,
            thisMonth: 'this'
        }, {
            index: 20,
            value: 1,
            active: false,
            thisMonth: 'this'
        }, {
            index: 21,
            value: 1,
            active: false,
            thisMonth: 'this'
        }
    ], [
        {
            index: 22,
            value: 1,
            active: false,
            thisMonth: 'this'
        }, {
            index: 23,
            value: 1,
            active: false,
            thisMonth: 'this'
        }, {
            index: 24,
            value: 1,
            active: false,
            thisMonth: 'this'
        }, {
            index: 25,
            value: 1,
            active: false,
            thisMonth: 'this'
        }, {
            index: 26,
            value: 1,
            active: false,
            thisMonth: 'this'
        }, {
            index: 27,
            value: 1,
            active: false,
            thisMonth: 'this'
        }, {
            index: 28,
            value: 1,
            active: false,
            thisMonth: 'this'
        }
    ], [
        {
            index: 29,
            value: 1,
            active: false,
            thisMonth: 'this'
        }, {
            index: 30,
            value: 1,
            active: false,
            thisMonth: 'this'
        }, {
            index: 31,
            value: 1,
            active: false,
            thisMonth: 'this'
        }, {
            index: 32,
            value: 1,
            active: false,
            thisMonth: 'this'
        }, {
            index: 33,
            value: 1,
            active: false,
            thisMonth: 'this'
        }, {
            index: 34,
            value: 1,
            active: false,
            thisMonth: 'this'
        }, {
            index: 35,
            value: 1,
            active: false,
            thisMonth: 'this'
        }
    ], [
        {
            index: 36,
            value: 1,
            active: false,
            thisMonth: 'this'
        }, {
            index: 37,
            value: 1,
            active: false,
            thisMonth: 'this'
        }, {
            index: 38,
            value: 1,
            active: false,
            thisMonth: 'this'
        }, {
            index: 39,
            value: 1,
            active: false,
            thisMonth: 'this'
        }, {
            index: 40,
            value: 1,
            active: false,
            thisMonth: 'this'
        }, {
            index: 41,
            value: 1,
            active: false,
            thisMonth: 'this'
        }, {
            index: 42,
            value: 1,
            active: false,
            thisMonth: 'this'
        }
    ],
])

// 获取月份最后一天
const getLastDay = (year: number, month: number): number => {
    const isLeapYear = ((year % 4) == 0) && ((year % 100) != 0) || ((year % 400) == 0)
    const maxDays = [1, 3, 5, 7, 8, 10, 12]
    const middleDays = [4, 6, 9, 11]
    month = Number(month)
    if (month == 2) {
        if (isLeapYear) {
            return 29
        } else {
            return 28
        }
    } else if (maxDays.includes(month)) {
        return 31
    } else if (middleDays.includes(month)) {
        return 30
    }
    return 30
}

// 侦听年月的变化
watch([year, month], ([newYear, newMonth]) => {
    // 获取月第一天和最后一天
    const lastDay = getLastDay(newYear, newMonth)
    const firstDate = new Date(`${newYear}-${newMonth}-1`)
    let preMonth = newMonth - 1
    let preYear = newYear
    if (preMonth <= 0) {
        preYear--
        preMonth = 12
    }
    const prelastDay = getLastDay(preYear, preMonth)
    const firstDay = firstDate.getDay() === 0 ? 7 : firstDate.getDay()
    let count = 2 - firstDay
    dayList.forEach(days => {
        days = days.map(day => {
            if (count <= 0) {
                // 上个月的日期
                day.thisMonth = 'pre'
                day.value = count + prelastDay
            } else if (count > lastDay) {
                // 下个月的日期
                day.thisMonth = 'next'
                day.value = count - lastDay
            } else {
                // 这个月的日期
                day.thisMonth = 'this'
                day.value = count
            }
            count++
            if (newYear === activeYear.value && newMonth === activeMonth.value && day.value === activeDay.value && day.thisMonth === 'this') {
                day.active = true
            } else {
                day.active = false
            }
            return day
        })
    })

}, { immediate: true })

// 选择年月
const yearList = ref<Array<number>>([])
const monthList = ref<Array<number>>([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12])
type yearMonth = 'year' | 'month' | 'day'
const yearMonthFlag = ref<yearMonth>("day")
const getYearMonth = (flag: yearMonth) => {
    yearMonthFlag.value = flag
    if (flag === 'year') {
        yearList.value = []
        for (let i = year.value; i <= year.value + 11; i++) {
            yearList.value.push(i)
        }
    }
}

// 点击年
const clickYear = (clickYear: number) => {
    year.value = clickYear
    yearMonthFlag.value = "month"
}

// 点击月份
const clickMonth = (clickMonth: number) => {
    month.value = clickMonth
    yearMonthFlag.value = 'day'
}

// 点击日期
const onClick = (index: number) => {
    dayList.forEach(days => {
        days.forEach(day => {
            if (day.index === index) {
                if (day.thisMonth === 'this') {
                    day.active = true
                } else if (day.thisMonth === 'pre') {
                    // 选择上个月
                    month.value--
                    if (month.value <= 0) {
                        year.value--
                        month.value = 12
                    }
                } else {
                    // 选择下个月
                    month.value++
                    if (month.value > 12) {
                        year.value++
                        month.value = 1
                    }
                }
                activeYear.value = year.value
                activeMonth.value = month.value
                activeDay.value = day.value
            } else {
                day.active = false
            }
        })
    })
    formatDate(activeYear.value, activeMonth.value, activeDay.value)
    show.value = false
}

// 去年
const preYear = () => {
    if (yearMonthFlag.value === 'year') {
        const beginYear = yearList.value[0] - 12
        yearList.value = []
        for (let i = beginYear; i <= beginYear + 11; i++) {
            yearList.value.push(i)
        }
    } else {
        year.value--
    }

}

// 上月
const preMonth = () => {
    if (month.value - 1 >= 1) {
        month.value--
    } else {
        year.value--
        month.value = 12
    }
}

// 明年
const nextYear = () => {
    if (yearMonthFlag.value === 'year') {
        const beginYear = yearList.value[0] + 12
        yearList.value = []
        for (let i = beginYear; i <= beginYear + 11; i++) {
            yearList.value.push(i)
        }
    } else {
        year.value++
    }
}

// 下个月
const nextMonth = () => {
    if (month.value + 1 <= 12) {
        month.value++
    } else {
        year.value++
        month.value = 1
    }
}
</script>